<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>块级作用域</title>
</head>
<body>
  <script>
      /*
      * 为什么需要块级作用域
      * 1. 变量提升，导致内层的tmp变量覆盖外层的tmp变量
      * 2. 用来计数的循环变量泄露为全局变量
      */

      var tmp = new Date()
      function f() {
        console.log(tmp) // undefined
        if (false) {
          var tmp = 'hello world'
        }
      }
      f() // 变量提升，导致内层的tmp变量覆盖外层的tmp变量

      var s = 'HELLO'
      for (var i = 0; i < s.length; i++) {
        console.log(s[i])
      }
      console.log(i) //5 使用var用来计数的循环变量泄露为全局变量

      /*
      * ES6 的块级作用域
      * 1. let实际上为JavaScript 新增了块级作用域
      * 2. ES6允许块级作用域的任意嵌套
      * 3. 外层作用域是无法读取内层作用域的变量
      * 4. 内层作用域可以定义外层作用域的同名变量
      * 5. 立即执行表达式(IIFE)不在必要
      */

      // function f1() {
      //   let n = 5
      //   if (true) {
      //     n = 10
      //   }
      //   console.log(n) // 5 因为不在相同的作用域所以打印的为5，不存在变量提升
      // }

      // {{{{
      //   let isName= 'hello world'
      //   console.log(isName) // 块级作用域是允许多层嵌套的
      // }
      //   console.log(isName) //Uncaught ReferenceError: isName is not defined 外层作用域是无法读取内层作用域的变量
      // }}}

      {{{
        let isA= 'hello world'
        console.log(isA) 
        {isA = 'test'
        console.log(isA)} //内层作用域可以定义外层作用域的同名变量
      }}}

      // 立即执行表达式（IIFE）
      // IIFE 写法
      (function () {
        var tmp = '...'
        console.log(tmp)
      }())
      // 块级作用域的写法
      {
        let tmp = '...'
        console.log(tmp)
      }

      /*
      * 块级作用域与函数声明
      */
      function f() {
        console.log('I am outSide!')
      }
      // (
      //   function () {
      //     if(false) {
      //       function f() {
      //         console.log('I am inSide!')
      //       }
      //     }
      //     f()
      //   }()
      // )
      {
        let a = 'secret'
        function f () {
          return console.log(a)
        }
      }
  </script>
</body>
</html>